#include "./../inc/timer.h"
#include "system.h"

#include <string.h>
#include <stdio.h>
#include <memory.h>
#include <stdlib.h>

typedef struct _UFO_Timer_Internal
{
	int microsecond;
	int repeatTime;
	long currentTime;
    void *userdata;
    int markRemove;
	TIMERPROC proc;
	UFO_View view;

	UFO_Handle handle;
}UFO_Timer_Internal, *PUFO_Timer_Internal;

typedef struct _UFO_Timer_Node
{
	struct _UFO_Timer_Node *lastNode;
	struct _UFO_Timer_Node *nextNode;
	UFO_Timer timer;
}UFO_Timer_Node, *PUFO_Timer_Node;

UFO_Timer_Node g_timer_list;

int InternalRemoveTimer(UFO_Timer timer)
{
	PUFO_Timer_Internal pTimer = ufoObjectFromHandle((UFO_Handle)timer);
	if (pTimer) {
		
		PUFO_Timer_Node timerNode = &g_timer_list;
		while (timerNode) {
			
			if (timerNode->timer == timer) {

				timerNode->lastNode->nextNode = timerNode->nextNode;
				if (timerNode->nextNode)
					timerNode->nextNode->lastNode = timerNode->lastNode;
				ufoCloseHandle((UFO_Handle)timerNode->timer);
				
				free(timerNode);
                
				break;
			}
            
			timerNode = timerNode->nextNode;
		}
        
		free(pTimer);
		return 1;
	}
	return 0;
}

int InternalAddTimer(UFO_Timer timer)
{
	PUFO_Timer_Node timerList = 0;
	PUFO_Timer_Node pNewNode = malloc(sizeof(UFO_Timer_Node));
	memset(pNewNode, 0, sizeof(UFO_Timer_Node));
	pNewNode->timer = timer;
    
	timerList = &g_timer_list;
	while (timerList->nextNode) {
		timerList = timerList->nextNode;
	}
    
	timerList->nextNode = pNewNode;
	pNewNode->lastNode = timerList;
    
	return 0;
}

int InternalProcessTimer()
{
	long nowTime = ufoGetCurTime();
	PUFO_Timer_Node timerNode = &g_timer_list;
	while (timerNode) {

		if (timerNode->timer) {//### not the root timer

			PUFO_Timer_Internal pTimer = ufoObjectFromHandle((UFO_Handle)timerNode->timer);
			if (pTimer){

                if (pTimer->markRemove) {//### be mark remove, call by ufoTimerDelete()
                    
                    timerNode = timerNode->nextNode;//### seek to next timer, because this time will be destroy
                    InternalRemoveTimer((UFO_Timer)pTimer->handle);
                    continue;//### continue
                }
				else if (pTimer->repeatTime) {
					
					int delta = nowTime - pTimer->currentTime;
					if (delta >= pTimer->microsecond) {//### overTime

						pTimer->currentTime = nowTime;
						if (pTimer->proc && !pTimer->markRemove) {//### fire callback
							pTimer->proc((UFO_Timer)pTimer->handle, delta, pTimer->userdata);
						}

						if (pTimer->view && !pTimer->markRemove) {//### notify view
							ufoViewSendMessage(pTimer->view, MSG_TIMER, pTimer->handle, pTimer->userdata);
						}

						--pTimer->repeatTime;
					}
				}
				else {
					ufoTimerDelete(timerNode->timer);
					timerNode = &g_timer_list;
				}
			}	
		}

		timerNode = timerNode->nextNode;
	}
	return 0;
}

UFO_Timer ufoTimerCreate(UFO_View view, int microsecond, int repeatTime, TIMERPROC proc, void *userdata)
{
	PUFO_Timer_Internal pTimer = malloc(sizeof(UFO_Timer_Internal));
	memset(pTimer, 0, sizeof(UFO_Timer_Internal));

	pTimer->view = view;
	pTimer->proc = proc;
    pTimer->userdata = userdata;
	pTimer->microsecond = microsecond;
	pTimer->repeatTime = repeatTime;
	pTimer->currentTime = ufoGetCurTime();
	pTimer->handle = ufoCreateHandle(UFO_ID_TIMER, pTimer);

	InternalAddTimer((UFO_Timer)pTimer->handle);

	return (UFO_Timer)pTimer->handle;
}

int ufoTimerDelete(UFO_Timer timer)
{
    PUFO_Timer_Internal pTimer = ufoObjectFromHandle((UFO_Handle)timer);
	if (pTimer) {
        pTimer->markRemove = 1;
    }
    
    return 0;
}